/*
 * administrador.cpp
 *
 *  Created on: 12/07/2014
 *      Author: migue
 */

#include <iostream>
#include <string.h>
#include <sstream>
#include <stdlib.h>
#include <unistd.h>

#include "../defines.h"
#include "../comun/ServidorRemoto.h"

#include "../comun/TokenCompartido.h"
#include "../comun/ParqueRemoto.h"
#include "../comun/SalaRemota.h"
#include "../ipcRemoto/SemaforoRemoto.h"
#include "../ipc/ColaMensajes.h"

using namespace std;

int id_admin;
int id_broker_conectado;
bool CClanzado = false;


void abrirParque() {
	//Semaforo sem(RUTA, 1, ID_MUTEX_PARQUE);
	//Parque parque;

	SemaforoRemoto sem(ID_MUTEX_PARQUE, id_admin, id_broker_conectado);
	ParqueRemoto parque(id_admin, id_broker_conectado);

	sem.wait();
	parque.abrirParque();
	sem.signal();
}

void cerrarParque() {
//	Semaforo sem(RUTA, 1, ID_MUTEX_PARQUE);
//	Parque parque;
	SemaforoRemoto sem(ID_MUTEX_PARQUE, id_admin, id_broker_conectado);
	ParqueRemoto parque(id_admin, id_broker_conectado);

	sem.wait();
	parque.cerrarParque();
	sem.signal();
}

void estadoDeParque() {
//	Semaforo sem(RUTA, 1, ID_MUTEX_PARQUE);
//	Parque parque;
	SemaforoRemoto sem(ID_MUTEX_PARQUE, id_admin, id_broker_conectado);
	ParqueRemoto parque(id_admin, id_broker_conectado);

	sem.wait();
	int cantActual = parque.personasDentro();
	bool abierto = parque.parqueAbierto();
	int cantRepuestos = parque.busesDeRepuesto();
	sem.signal();

	cout << "Capacidad :" << CANT_MAX_PARQUE << endl;
	cout << "Estado: ";
	if (abierto) {
		cout << "Abierto." << endl;
	}
	else {
		cout << "Cerrado." << endl;
	}

	cout << "Personas Dentro: " << cantActual << endl;

	cout << "Buses Repuesto Disponibles: " << cantRepuestos << endl << endl;


	// mostrando las salas

	int cantPers;
	Tipos::EstadoBUS estBus;

	for (int i = 0; i < CANT_ENTRADAS ; ++i) {
		int numSala = i+1;

//		SalaDePersonas salaEnt(numSala, Tipos::LUGAR_ENTRADA);
//		Semaforo semEnt(RUTA, 1, ID_MUTEX_SALA_ENT(numSala));

		SalaRemota salaEnt(numSala, Tipos::LUGAR_ENTRADA, id_admin, id_broker_conectado);
		SemaforoRemoto semEnt(ID_MUTEX_SALA_ENT(numSala), id_admin, id_broker_conectado);


//		SalaDePersonas salaZoo(i+1, Tipos::LUGAR_ZOO);
//		Semaforo semZoo(RUTA, 1, ID_MUTEX_SALA_ZOO(numSala));

		SalaRemota salaZoo(numSala, Tipos::LUGAR_ZOO, id_admin, id_broker_conectado);
		SemaforoRemoto semZoo(ID_MUTEX_SALA_ZOO(numSala), id_admin, id_broker_conectado);


		cout << "SalaEnt " << numSala <<": ";

		semEnt.wait();
		cantPers = salaEnt.cantidadDePersonas();
		estBus = salaEnt.estadoBUS();
		semEnt.signal();


		cout << cantPers << " pers. " ;

		if (estBus == Tipos::BUS_PARADO) {
			cout << " - BUS PARADO - ";
		}
		else if (estBus == Tipos::BUS_ACTIVO ){
			cout << " -            - ";
		}
		else if (estBus == Tipos::BUS_SUBIENDO_PERS ){
			cout << " -  SUBIENDO  - ";
		}
		else if (estBus == Tipos::BUS_BAJANDO_PERS ){
			cout << " -  BAJANDO   - ";
		}
		else {
			cout << " - BUS_ERROR  - ";
		}


		cout << "| SalaZoo " << numSala <<": ";

		semZoo.wait();
		cantPers = salaZoo.cantidadDePersonas();
		estBus = salaZoo.estadoBUS();
		semZoo.signal();

		cout << cantPers << " pers. " ;

		if (estBus == Tipos::BUS_PARADO) {
			cout << " - BUS PARADO - ";
		}
		else if (estBus == Tipos::BUS_ACTIVO ){
			cout << " -            - ";
		}
		else if (estBus == Tipos::BUS_SUBIENDO_PERS ){
			cout << " -  SUBIENDO  - ";
		}
		else if (estBus == Tipos::BUS_BAJANDO_PERS ){
			cout << " -  BAJANDO   - ";
		}
		else {
			cout << " - BUS_ERROR  - ";
		}

		cout << endl;
	}
}

void cambiarCaminos(int cantCaminos) {
	// TODO Hacer...
}


void cambiarCapacidad(int nuevaCapacidad) {
	// TODO Hacer
}

void agregarRepuestos(int cantRepuestos) {

	if (cantRepuestos <= 0) {
		cout << "No se puede agregar la cantidad de \"" << cantRepuestos << "\" repuestos. "<< endl;
	}

	SemaforoRemoto sem(ID_MUTEX_PARQUE, id_admin, id_broker_conectado);
	ParqueRemoto parque(id_admin,id_broker_conectado);

	sem.wait();
	parque.agregarBusesDeRepuesto(cantRepuestos);
	sem.signal();

	int pid;
	for (int i = 0; i < cantRepuestos; ++i ) {

		pid = fork();

		if (pid == 0) {
			execlp("./bus", "BUS", NULL);
			perror("No se pudo iniciar proceso De BUS de Repuesto (desde administrador)");
			exit(EXIT_FAILURE);
		}
	}


	cout << "Agregados " << cantRepuestos << " al Parque."<< endl;
}

void lanzarCC() {
	ServidorRemoto serv;

	id_admin = serv.pedirIdAdministrador();
	id_broker_conectado = serv.idBrokerConectado();

	stringstream idAux;
	idAux << id_admin;
	int pid = fork();
	if (pid == 0) {
		execlp("./conexBrokerCliente", "conexBrokerCliente",
				idAux.str().c_str(), "E", NULL);
		perror("Error en el exec conexionBrokerCliente");
		exit(1);
	}
	pid = fork();
	if (pid == 0) {
		execlp("./conexBrokerCliente", "conexBrokerCliente",
				idAux.str().c_str(), "R", NULL);
		perror("Error en el exec conexionBrokerCliente");
		exit(1);
	}

	CClanzado = true;
}

void detenerCC() {
	if (CClanzado == false)
		return;

	ColaMensajes _colaEnvio(RUTA, COLASISTEMA);
	MENSAJE msj;


	msj.destinatario = id_admin;
	msj.destinatarioFinal = id_broker_conectado;
	msj.origen = id_admin;

	msj.tipo = Tipos::MSJ_IPC;
	msj._ipc.op_ipc = TIPO_FINALIZAR;

	_colaEnvio.enviar(&msj, TAM_MENSAJE);
}

void estadoDeParque2() {
	TokenCompartido token;

	token.mostrarEstado();
}

void pausarBroker() {
	TokenCompartido token;
	token.pausarBroker();
}

void retomarBroker() {
	TokenCompartido token;
	token.retomarBroker();
}

int main(int argc, char** argv) {

	if (argc < 2) {
		cout << "Se debe ingresar alguno de los siguientes parametros:" << endl;
		cout << "-a : abrir Parque" << endl;
		cout << "-c : cerrar Parque " << endl;
		cout << "-e : estado de Parque" << endl;
		cout << "-b X: agregar X repuestos de bueses al parque" << endl;
		cout << "-p:  pausar el broker actual" << endl;
		cout << "-v:  retoma el broker actual con su tarea" << endl;
		cout << "-t X: cambiar la capacidad del Parque por X cantidad de personas" << endl;

		return 1;
	}



	if (strcmp(argv[1], "-a") == 0) {
		lanzarCC();
		abrirParque();
	}
	else if (strcmp(argv[1], "-c") == 0) {
		lanzarCC();
		cerrarParque();
	}
	else if (strcmp(argv[1], "-e") == 0) {
		estadoDeParque2();
	}
	else if (strcmp(argv[1], "-p") == 0) {
		pausarBroker();
	}
	else if (strcmp(argv[1], "-v") == 0) {
		retomarBroker();
	}
	else if (strcmp(argv[1], "-b") == 0 && argc == 3) {
		lanzarCC();
		agregarRepuestos(atoi(argv[2]));
	}
	else {
		cout << "Parametro desconocido" << endl;
	}

	detenerCC();


	return 0;
}
